import sys
import random
import pygame
from pygame.locals import *

# 初始化pygame
pygame.init()
fpsClock = pygame.time.Clock()

# 创建窗口
playSurface = pygame.display.set_mode((640, 480))
pygame.display.set_caption('贪食蛇')

# 定义颜色
redColor = pygame.Color(255, 0, 0)
blackColor = pygame.Color(0, 0, 0)
whiteColor = pygame.Color(255, 255, 255)
greyColor = pygame.Color(100, 100, 100)

# 绘制游戏结束
def drawGameOver(playSurface, score):
    gameOverFont = pygame.font.SysFont('arial', 72)
    gameOverSurf = gameOverFont.render('Game Over', True, greyColor)
    gameOverRect = gameOverSurf.get_rect()
    gameOverRect.midtop = (320, 125)
    playSurface.blit(gameOverSurf, gameOverRect)
    scoreFont = pygame.font.SysFont('arial', 48)
    scoreSurf = scoreFont.render('SCORE:' + str(score), True, greyColor)
    scoreRect = scoreSurf.get_rect()
    scoreRect.midtop = (320, 225)
    playSurface.blit(scoreSurf, scoreRect)
    pygame.display.flip()
    pygame.time.wait(5000)
    pygame.quit()
    sys.exit()

# 判断是否可以改变方向
def checkChangeDirection(currentDirection, newDirection):
    if(currentDirection == 'right' and not newDirection == 'left'):
        return newDirection
    elif(currentDirection == 'left' and not newDirection == 'right'):
        return newDirection
    elif(currentDirection == 'up' and not newDirection == 'down'):
        return newDirection
    elif(currentDirection == 'down' and not newDirection == 'up'):
        return newDirection
    else: return currentDirection

# 根据按键改变方向
def getDirectionByKeydown(key,currentDirection):
    if(key == K_RIGHT or key == ord('d')):
        return 'right'
    elif(key == K_LEFT or key == ord('a')):
        return 'left'
    elif(key == K_UP or key == ord('w')):
        return 'up'
    elif(key == K_DOWN or key == ord('s')):
        return 'down'
    elif(key == K_ESCAPE):
        pygame.event.post(pygame.event.Event(QUIT))
    else:
        return currentDirection

# 移动蛇头
def moveSnake(direction, snakePosition, snakeSegments):
    if direction == 'right':
        snakePosition[0] += 20
    if direction == 'left':
        snakePosition[0] -= 20
    if direction == 'up':
        snakePosition[1] -= 20
    if direction == 'down':
        snakePosition[1] += 20
    # 新蛇头位置安装到蛇身上
    snakeSegments.insert(0, list(snakePosition))

# 检查是否游戏结束
def checkGameOver(snakePosition, snakeSegments):
    # 碰撞检测 - 边界
    if snakePosition[0] >= 640 or snakePosition[0] < 0 or snakePosition[1] >= 480 or snakePosition[1] < 0:
        drawGameOver(playSurface, score)

    # 碰撞检测 - 自身
    for body in snakeSegments[1:]:
        if snakePosition == body:
            drawGameOver(playSurface, score)

# 生成新的食物
def newFood():
    x = random.randrange(0, 640, 20)
    y = random.randrange(0, 480, 20)
    return [x, y]

#  绘制界面
def drawSurface(playSurface, foodPosition, snakeSegments):
    # 清屏并填充背景色
    playSurface.fill(blackColor)
    # 绘制蛇身
    for position in snakeSegments:
        pygame.draw.rect(playSurface, whiteColor, Rect(position[0], position[1], 20, 20))
    # 绘制食物
    pygame.draw.rect(playSurface, redColor, Rect(foodPosition[0], foodPosition[1], 20, 20))
    # 更新屏幕
    pygame.display.flip()
    # 控制帧率
    speed = 6 + len(snakeSegments) // 4
    fpsClock.tick(speed)
    return


# 初始化变量
snakePosition = [100, 100] # 蛇头位置
snakeSegments = [[100, 100], [80, 100], [60, 100]] # 蛇身位置
foodPosition = [random.randrange(0, 640, 20), random.randrange(0, 480, 20)] # 食物位置
foodNum = 1 # 食物数量
direction = 'right' # 初始方向
changeDirection = direction # 转向
score = 0 # 得分

# 游戏主循环
while True:
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()
        elif event.type == KEYDOWN:
            # 根据按键改变方向
            changeDirection = getDirectionByKeydown(event.key, direction)

    # 判断是否可以改变方向
    direction = checkChangeDirection(direction, changeDirection)

    # 移动蛇头
    moveSnake(direction, snakePosition, snakeSegments)

    # 检查是否吃到食物
    if snakePosition == foodPosition:
        foodNum = 0
        score += 1
    else:
        snakeSegments.pop()  # 否则删除尾部

    # 检查是否游戏结束
    checkGameOver(snakePosition, snakeSegments)

    # 随机刷新食物
    if foodNum == 0:
        foodPosition = newFood()
        foodNum = 1 # 恢复食物库存

    #  绘制界面
    drawSurface(playSurface, foodPosition, snakeSegments)